package com.rankeiot.core.job;

import cn.hutool.core.date.LocalDateTimeUtil;
import lombok.Data;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.scheduling.support.CronTrigger;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;

/**
 * @author desire
 */
@Data
public class JobMeta implements Runnable {

    private String name;
    private String title;
    private String desc;
    private String cron;
    private Runnable job;
    CronExpression exp;
    private ScheduledFuture sf;

    public JobMeta(String name, String cron, Runnable job) {
        this.name = name;
        this.job = job;
        this.cron = cron;
        exp = CronExpression.parse(cron);
    }

    public Date nextTime() {
        LocalDateTime next = exp.next(LocalDateTimeUtil.now());
        return Date.from(next.atZone(ZoneId.systemDefault()).toInstant());
    }

    @Override
    public void run() {
        runJob(false);
    }

    /**
     * 执行任务
     *
     * @param force 是否强制执行，在强制执行的情况下，不到直接也执行
     */
    public void runJob(boolean force) {
        if (!JobManager.defaultTaskHandler.before(name, nextTime(), force)) {
            return;
        }
        long start = System.currentTimeMillis();
        Exception taskException = null;
        try {
            job.run();
        } catch (Exception e) {
            e.printStackTrace();
            taskException = e;
        } finally {
            JobManager.defaultTaskHandler.after(name, start, taskException);
        }
    }

    public void schedule(TaskScheduler scheduler) {
        cancelSchedule();
        sf = scheduler.schedule(this, new CronTrigger(getCron()));
    }

    public void cancelSchedule() {
        if (this.sf != null) {
            sf.cancel(true);
        }
    }
}
